/**
 * 
 */
package u.can.i.up.db.mongo;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;

import u.can.i.up.utils.Configuration;
import u.can.i.up.utils.Constants;
import u.can.i.up.utils.StringUtils;

/**
 * @author yanwei
 * @time: 2012-11-6 上午11:01:01
 * @description Mongodb Conection Factory
 * 
 */
public class MongodbConnFactory {

	private static final Logger LOGGER = LogManager.getLogger();

	private static final String MONGODB_URIS = Configuration.get(Constants.MONGODB_URIS, "localhost:27017");

	private static final String DBNAME = Configuration.get(Constants.MONGODB_NAME, "tase");

	private static final String USERNAME = Configuration.get(Constants.MONGODB_USERNAME, "softsec");

	private static final String PASSWORD = Configuration.get(Constants.MONGODB_PASSWORD, "62283748");

	private static DB mongodb;

	static {
		mongodb = getConnection();
	}

	public MongodbConnFactory() {
	}

	/**
	 * get MongoDB
	 * 
	 * @return DB
	 */
	public static final DB getDB() {
		return mongodb;
	}

	/**
	 * get Mongo DBcollection
	 * 
	 * @param collectionName
	 * @return
	 */
	public static final DBCollection getCollection(String collectionName) throws DbUtilsException {
		int getConnectionTimes = 5;
		int connectTime = 0;
		for (connectTime = 0; connectTime <= getConnectionTimes; connectTime++) {
			try {
				mongodb.getStats();
				break;
			} catch (Exception e) {
				if (connectTime == getConnectionTimes) {
					LOGGER.error("failed to get mongoDB connection : " + e.getMessage());

				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {
					LOGGER.error("failed to sleep for 1s to get mongoDB connection : " + e.getMessage());
					throw new DbUtilsException("failed to sleep for 1s to get mongoDB connection : " + e.getMessage(),
							e);
				}
				mongodb = null;
				mongodb = getConnection();
			}
		}
		return mongodb.getCollection(collectionName);
	}

	public static DB getConnection() {
		DB mongodb = null;
		// parse mongodb server uri
		String[] serverArray = MONGODB_URIS.trim().split(";");
		if (serverArray.length > 1) {
			List<ServerAddress> serverAddrList = new ArrayList<ServerAddress>();
			for (String server : serverArray) {
				if (!StringUtils.isEmpty(server)) {
					try {
						serverAddrList.add(
								new ServerAddress(server.split(":")[0].trim(), Integer.parseInt(server.split(":")[1])));
						System.out.println(serverAddrList);
					} catch (NumberFormatException nfe) {
						LOGGER.error("Failed to parse mongodb server configuration : " + MONGODB_URIS + " : "
								+ nfe.getMessage(), nfe);
						throw new RuntimeException("Failed to parse mongodb server configuration : " + MONGODB_URIS
								+ " : " + nfe.getMessage(), nfe);
					} catch (UnknownHostException uhe) {
						LOGGER.error("Failed to connect mongodb server : " + MONGODB_URIS + " : " + uhe.getMessage(),
								uhe);
						throw new RuntimeException(
								"Failed to connect mongodb server : " + MONGODB_URIS + " : " + uhe.getMessage(), uhe);
					}
				}
			}
			// mongodb connection configuration

			// initialize mongo client
			MongoClient client = new MongoClient(serverAddrList);
			mongodb = client.getDB(DBNAME);
			// Exceptions are raised for network issues, and server errors;
			// waits for at least 2 servers for the write operation
			// for production use
			mongodb.setWriteConcern(WriteConcern.REPLICAS_SAFE);
		} else {
			try {
				MongoClient client = new MongoClient(serverArray[0].split(":")[0].trim(),
						Integer.parseInt(serverArray[0].split(":")[1]));
				mongodb = client.getDB(DBNAME);
				// Exceptions are raised for network issues, and server errors;
				// waits on a server for the write operation
				// for development use
				mongodb.setWriteConcern(WriteConcern.SAFE);
			} catch (NumberFormatException nfe) {
				LOGGER.error(
						"Failed to parse mongodb server configuration : " + MONGODB_URIS + " : " + nfe.getMessage(),
						nfe);
				throw new RuntimeException(
						"Failed to parse mongodb server configuration : " + MONGODB_URIS + " : " + nfe.getMessage(),
						nfe);
			} catch (UnknownHostException uhe) {
				LOGGER.error("Failed to connect mongodb server : " + MONGODB_URIS + " : " + uhe.getMessage(), uhe);
				throw new RuntimeException(
						"Failed to connect mongodb server : " + MONGODB_URIS + " : " + uhe.getMessage(), uhe);
			}
		}

		if (!mongodb.authenticate(USERNAME, PASSWORD.toCharArray())) {
			LOGGER.error("Invalid username or password to login mongodb : " + MONGODB_URIS);
			throw new RuntimeException("Invalid username or password to login mongodb : " + MONGODB_URIS);
		}
		return mongodb;
	}
}
